package com.southminority.ethnic.service.document.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
import com.southminority.ethnic.common.exception.BusinessException;
import com.southminority.ethnic.common.result.PageResult;
import com.southminority.ethnic.dto.DocumentDTO;
import com.southminority.ethnic.mapper.document.DocumentMapper;
import com.southminority.ethnic.pojo.Document;
import com.southminority.ethnic.service.document.DocumentService;
import com.southminority.ethnic.controller.document.vo.DocumentVO;
import com.southminority.ethnic.controller.document.vo.FileTypeInfoVO;
import com.southminority.ethnic.vo.ShareInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 古籍文献服务实现类.
 * <p>
 * 实现了 {@link DocumentService} 接口，负责处理所有与古籍文献相关的业务逻辑。
 * 包括数据查询、转换、增删改查以及与文件相关的操作。
 * 
 * @author SouthMinority
 */
@Slf4j
@Service
public class DocumentServiceImpl implements DocumentService {

    private final DocumentMapper documentMapper;
    private final ObjectMapper objectMapper; // 用于处理JSON字符串和Java对象之间的转换

    public DocumentServiceImpl(DocumentMapper documentMapper, ObjectMapper objectMapper) {
        this.documentMapper = documentMapper;
        this.objectMapper = objectMapper;
    }

    // =================================================================================
    // ==                             前端展示相关方法 (Public API)                     ==
    // =================================================================================

    @Override
    public DocumentVO getFeaturedDocument() {
        // 构建查询条件：状态为已发布(1)，设置为首页展示(1)，且首页排序号大于0
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .eq("is_featured", 1)
               .gt("homepage_order", 0)
               .orderByAsc("homepage_order") // 按排序号升序
               .last("LIMIT 1"); // 只取第一条
        
        Document document = documentMapper.selectOne(wrapper);
        if (document == null) {
            // 如果没有找到任何特色文献，可以根据业务需求返回null或抛出异常
            // 这里选择抛出业务异常，前端可以捕获并进行相应处理
            throw new BusinessException("暂无古籍文献信息");
        }
        
        return convertToVO(document);
    }

    @Override
    public List<DocumentVO> getHomepageDocumentList() {
        // 构建查询条件：已发布、首页展示、排序号大于0
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .eq("is_featured", 1)
               .gt("homepage_order", 0)
               .orderByAsc("homepage_order"); // 按排序号升序获取整个列表
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        // 将Document实体列表转换为DocumentVO视图对象列表
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    public DocumentVO getDocumentDetail(Long id) {
        Document document = documentMapper.selectById(id);
        // 校验文献是否存在或已被删除
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }
        
        // 每次获取详情时，异步增加一次浏览次数
        increaseViewCount(id);
        
        return convertToVO(document);
    }

    @Override
    public List<DocumentVO> getDocumentList() {
        // 构建查询条件：状态为已发布，按自定义排序号和创建时间排序
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    public List<DocumentVO> getDocumentListByCategory(Long categoryId) {
        // 构建查询条件：已发布、指定分类ID
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .eq("category_id", categoryId)
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    public List<DocumentVO> getDocumentListByType(String documentType) {
        // 构建查询条件：已发布、指定文献类型
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .eq("document_type", documentType)
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    public List<DocumentVO> getDocumentListByDynasty(String dynasty) {
        // 构建查询条件：已发布、指定朝代
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .eq("dynasty", dynasty)
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    public List<DocumentVO> searchDocuments(String keyword) {
        // 简单的前置校验，避免无效的数据库查询
        if (!StringUtils.hasText(keyword)) {
            return Collections.emptyList();
        }
        
        // 构建模糊查询条件：已发布，且标题、作者、描述或关键词中包含keyword
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1)
               .and(qw -> qw.like("title", keyword)
                           .or().like("author", keyword)
                           .or().like("description", keyword)
                           .or().like("keywords", keyword))
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    @Override
    @Transactional // 声明为事务方法，确保数据一致性
    public void increaseViewCount(Long id) {
        Document document = documentMapper.selectById(id);
        if (document != null && document.getStatus() != -1) {
            // 安全地增加浏览次数，处理null的情况
            document.setViewCount((document.getViewCount() == null ? 0 : document.getViewCount()) + 1);
            documentMapper.updateById(document);
        }
    }

    @Override
    @Transactional
    public void increaseDownloadCount(Long id) {
        Document document = documentMapper.selectById(id);
        if (document != null && document.getStatus() != -1) {
            // 安全地增加下载次数
            document.setDownloadCount((document.getDownloadCount() == null ? 0 : document.getDownloadCount()) + 1);
            documentMapper.updateById(document);
        }
    }


    // =================================================================================
    // ==                             后台管理相关方法 (Admin API)                      ==
    // =================================================================================

    @Override
    public PageResult<DocumentVO> getDocumentPage(Integer page, Integer size, String keyword, Long categoryId, String documentType, String dynasty, Integer status) {
        // 1. 创建MyBatisPlus的分页对象
        Page<Document> pageObj = new Page<>(page, size);
        
        // 2. 构建动态查询条件
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        
        // 关键词模糊查询（标题、作者、描述、关键词）
        if (StringUtils.hasText(keyword)) {
            wrapper.and(qw -> qw.like("title", keyword)
                               .or().like("author", keyword)
                               .or().like("description", keyword)
                               .or().like("keywords", keyword));
        }
        
        // 精确匹配筛选条件
        if (categoryId != null) {
            wrapper.eq("category_id", categoryId);
        }
        if (StringUtils.hasText(documentType)) {
            wrapper.eq("document_type", documentType);
        }
        if (StringUtils.hasText(dynasty)) {
            wrapper.eq("dynasty", dynasty);
        }
        
        // 状态筛选：如果传入status，则按status筛选；否则默认不显示已删除的记录
        if (status != null) {
            wrapper.eq("status", status);
        } else {
            wrapper.ne("status", -1); 
        }
        
        // 3. 设置排序规则：优先按首页推荐，然后按首页顺序，再按通用顺序，最后按创建时间
        wrapper.orderByDesc("is_featured")
               .orderByAsc("homepage_order")
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        // 4. 执行分页查询
        IPage<Document> pageResult = documentMapper.selectPage(pageObj, wrapper);
        
        // 5. 将查询结果的实体列表转换为VO列表
        List<DocumentVO> voList = pageResult.getRecords().stream()
                                           .map(this::convertToVO)
                                           .collect(Collectors.toList());
        
        // 6. 封装并返回自定义的分页结果对象
        return PageResult.<DocumentVO>builder()
                .current(pageResult.getCurrent())
                .size(pageResult.getSize())
                .total(pageResult.getTotal())
                .pages(pageResult.getPages())
                .records(voList)
                .build();
    }

    @Override
    @Transactional
    public DocumentVO createDocument(DocumentDTO documentDTO) {
        Document document = new Document();
        BeanUtils.copyProperties(documentDTO, document);
        
        // 为新创建的文档设置合理的默认值，避免数据库出现null
        if (document.getViewCount() == null) document.setViewCount(0);
        if (document.getDownloadCount() == null) document.setDownloadCount(0);
        if (document.getIsFeatured() == null) document.setIsFeatured(0);
        if (document.getHomepageOrder() == null) document.setHomepageOrder(0);
        if (document.getSortOrder() == null) document.setSortOrder(0);
        if (document.getStatus() == null) document.setStatus(1); // 默认为已发布状态
        
        documentMapper.insert(document);
        // 返回转换后的VO对象，以便前端直接使用
        return convertToVO(document);
    }

    @Override
    @Transactional
    public DocumentVO updateDocument(Long id, DocumentDTO documentDTO) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }
        
        BeanUtils.copyProperties(documentDTO, document);
        document.setId(id); // 确保ID不会被覆盖
        document.setUpdateTime(LocalDateTime.now()); // 手动更新修改时间
        
        documentMapper.updateById(document);
        return convertToVO(document);
    }

    @Override
    @Transactional
    public boolean deleteDocument(Long id) {
        Document document = documentMapper.selectById(id);
        if (document == null) {
            throw new BusinessException("古籍文献不存在");
        }
        
        // 使用逻辑删除（软删除），将状态标记为-1
        document.setStatus(-1);
        document.setUpdateTime(LocalDateTime.now());
        return documentMapper.updateById(document) > 0;
    }

    @Override
    @Transactional
    public boolean batchDeleteDocument(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("删除的古籍文献ID列表不能为空");
        }
        
        // 先查询出所有待删除的实体
        List<Document> documentList = documentMapper.selectBatchIds(ids);
        if (documentList.isEmpty()) {
            throw new BusinessException("未找到要删除的古籍文献");
        }
        
        LocalDateTime now = LocalDateTime.now();
        // 遍历列表，逐个设置状态和更新时间
        documentList.forEach(document -> {
            document.setStatus(-1);
            document.setUpdateTime(now);
        });
        
        // 循环批量更新。注意：MyBatisPlus没有直接的批量更新方法，需要逐条执行或自定义SQL。
        // 为保证逻辑清晰和通用性，此处采用循环。如果性能要求高，可以自定义Mapper方法。
        int updatedCount = 0;
        for (Document document : documentList) {
            updatedCount += documentMapper.updateById(document);
        }
        
        // 确认所有记录都已成功更新
        return updatedCount == documentList.size();
    }

    @Override
    @Transactional
    public boolean updateDocumentStatus(Long id, Integer status) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }
        
        document.setStatus(status);
        document.setUpdateTime(LocalDateTime.now());
        return documentMapper.updateById(document) > 0;
    }

    @Override
    @Transactional
    public boolean setDocumentFeatured(Long id, Integer isFeatured) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }
        
        document.setIsFeatured(isFeatured);
        document.setUpdateTime(LocalDateTime.now());
        return documentMapper.updateById(document) > 0;
    }

    @Override
    @Transactional
    public boolean setDocumentHomepageOrder(Long id, Integer homepageOrder) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }
        
        document.setHomepageOrder(homepageOrder);
        document.setUpdateTime(LocalDateTime.now());
        return documentMapper.updateById(document) > 0;
    }

    @Override
    public List<DocumentVO> getAllDocumentList() {
        // 获取所有未被逻辑删除的文献
        QueryWrapper<Document> wrapper = new QueryWrapper<>();
        wrapper.ne("status", -1)
               .orderByDesc("is_featured")
               .orderByAsc("homepage_order")
               .orderByAsc("sort_order")
               .orderByDesc("create_time");
        
        List<Document> documentList = documentMapper.selectList(wrapper);
        return documentList.stream()
                          .map(this::convertToVO)
                          .collect(Collectors.toList());
    }

    // =================================================================================
    // ==                             私有辅助方法 (Private Helpers)                      ==
    // =================================================================================

    /**
     * 将 Document (POJO) 实体对象转换为 DocumentVO (View Object) 视图对象.
     * <p>
     * 这个方法负责处理复杂字段的转换，例如：
     * <ul>
     *     <li>JSON字符串（如image_urls）转换为List</li>
     *     <li>逗号分隔的字符串（如tags）转换为List</li>
     *     <li>状态码、类型码等转换为可读的描述文本</li>
     * </ul>
     *
     * @param document 数据库查询出的古籍文献实体对象。
     * @return 转换后用于前端展示的视图对象。
     */
    private DocumentVO convertToVO(Document document) {
        if (document == null) return null;
        DocumentVO vo = new DocumentVO();
        BeanUtils.copyProperties(document, vo);
        
        // 手动映射`abstract`字段，因为`abstract`是Java的关键字，所以POJO中字段名为`abstractText`
        vo.setAbstractText(document.getAbstractText());
        
        try {
            // 安全地将存储为JSON字符串的图片URL列表，反序列化为Java的List<String>
            if (StringUtils.hasText(document.getImageUrls())) {
                List<String> imageUrls = objectMapper.readValue(
                    document.getImageUrls(), 
                    new TypeReference<List<String>>() {}
                );
                vo.setImageUrls(imageUrls);
            }
            
            // 将以逗号分隔的标签字符串，转换为List<String>
            if (StringUtils.hasText(document.getTags())) {
                List<String> tags = Arrays.asList(document.getTags().split(","));
                vo.setTags(tags.stream().map(String::trim).collect(Collectors.toList()));
            }
        } catch (Exception e) {
            log.error("转换古籍文献VO时，解析JSON字段失败: documentId={}", document.getId(), e);
        }
        
        // 为状态码、类型码等添加可读的文本描述，方便前端直接展示
        vo.setStatusDesc(getStatusDesc(document.getStatus()));
        vo.setDocumentTypeDesc(getDocumentTypeDesc(document.getDocumentType()));
        vo.setDynastyDesc(getDynastyDesc(document.getDynasty()));
        
        return vo;
    }

    /**
     * 根据状态码获取可读的状态描述.
     */
    private String getStatusDesc(Integer status) {
        if (status == null) return "未知";
        switch (status) {
            case 1: return "已发布";
            case 0: return "草稿";
            case -1: return "已删除";
            default: return "未知";
        }
    }

    /**
     * 根据文献类型码获取可读的类型描述.
     */
    private String getDocumentTypeDesc(String documentType) {
        if (!StringUtils.hasText(documentType)) return "";
        // 这里可以扩展为一个更复杂的映射，例如从数据库或缓存中读取
        switch (documentType) {
            case "古籍": return "古代典籍";
            case "手稿": return "手写稿件";
            case "碑刻": return "石碑刻文";
            case "族谱": return "家族谱系";
            case "史料": return "历史资料";
            case "民间文学": return "民间文学作品";
            default: return documentType;
        }
    }

    /**
     * 获取朝代描述（目前直接返回原值，可扩展）.
     */
    private String getDynastyDesc(String dynasty) {
        if (!StringUtils.hasText(dynasty)) return "";
        // 未来可以根据需要添加朝代的详细描述或关联其他信息
        return dynasty;
    }

    @Override
    public FileTypeInfoVO getDocumentFileTypes(Long id) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }

        FileTypeInfoVO fileTypeInfo = new FileTypeInfoVO();
        
        // 初始化所有布尔字段为false，防止NPE
        fileTypeInfo.setHasPdf(false);
        fileTypeInfo.setHasOtherFile(false);
        fileTypeInfo.setHasImages(false);
        fileTypeInfo.setHasAudio(false);
        fileTypeInfo.setHasVideo(false);
        fileTypeInfo.setHasAttachments(false);
        
        // 逻辑核心：检查各种文件URL是否存在，并填充FileTypeInfoVO
        
        // 1. 优先检查新的`primary_file_url`字段，它支持多种文件类型
        if (StringUtils.hasText(document.getPrimaryFileUrl())) {
            String fileType = document.getPrimaryFileType();
            if ("pdf".equalsIgnoreCase(fileType)) {
                fileTypeInfo.setHasPdf(true);
                fileTypeInfo.setPdfUrl(document.getPrimaryFileUrl());
                fileTypeInfo.setPdfSize(document.getPrimaryFileSize());
            } else {
                // 如果不是PDF，则认为是其他类型的文件（如PPT, DOCX等）
                fileTypeInfo.setHasOtherFile(true);
                fileTypeInfo.setOtherFileUrl(document.getPrimaryFileUrl());
                fileTypeInfo.setOtherFileType(fileType);
                fileTypeInfo.setOtherFileName(document.getPrimaryFileName());
                fileTypeInfo.setOtherFileSize(document.getPrimaryFileSize());
            }
        } 
        // 2. 如果`primary_file_url`为空，则检查旧的`pdf_url`字段以兼容老数据
        else if (StringUtils.hasText(document.getPdfUrl())) {
            fileTypeInfo.setHasPdf(true);
            fileTypeInfo.setPdfUrl(document.getPdfUrl());
            fileTypeInfo.setPdfSize(0L); // 旧字段没有大小信息，默认为0
        }

        // 3. 检查图片文件（JSON数组）
        if (StringUtils.hasText(document.getImageUrls())) {
            try {
                List<String> imageUrls = objectMapper.readValue(document.getImageUrls(), new TypeReference<>() {});
                if (imageUrls != null && !imageUrls.isEmpty()) {
                    fileTypeInfo.setHasImages(true);
                    fileTypeInfo.setImageUrls(imageUrls);
                    fileTypeInfo.setImageCount(imageUrls.size());
                }
            } catch (Exception e) {
                log.warn("解析文档ID {} 的图片URLs失败: {}", id, e.getMessage());
            }
        }

        // 4. 检查音频和视频文件
        fileTypeInfo.setHasAudio(StringUtils.hasText(document.getAudioUrl()));
        fileTypeInfo.setAudioUrl(document.getAudioUrl());
        fileTypeInfo.setHasVideo(StringUtils.hasText(document.getVideoUrl()));
        fileTypeInfo.setVideoUrl(document.getVideoUrl());

        // 5. 检查附件（JSON数组）
        if (StringUtils.hasText(document.getAttachmentUrls())) {
            try {
                List<Map<String, String>> attachmentList = objectMapper.readValue(document.getAttachmentUrls(), new TypeReference<>() {});
                if (attachmentList != null && !attachmentList.isEmpty()) {
                    fileTypeInfo.setHasAttachments(true);
                    fileTypeInfo.setAttachmentCount(attachmentList.size());
                }
            } catch (Exception e) {
                log.warn("解析文档ID {} 的附件URLs失败: {}", id, e.getMessage());
            }
        }
        
        // 6. 根据以上检查结果，构建一个可供前端展示的、包含所有可用文件类型的列表
        fileTypeInfo.updateAvailableTypes();

        log.info("获取文档ID {} 的文件类型信息: {}", id, fileTypeInfo);
        return fileTypeInfo;
    }

    @Override
    public ShareInfoVO generateShareInfo(Long id) {
        Document document = documentMapper.selectById(id);
        if (document == null || document.getStatus() == -1) {
            throw new BusinessException("古籍文献不存在");
        }

        ShareInfoVO shareInfo = new ShareInfoVO();
        shareInfo.setDocumentId(id);
        shareInfo.setTitle(document.getTitle());
        // 截取部分描述作为分享摘要
        shareInfo.setDescription(StringUtils.hasText(document.getDescription()) && document.getDescription().length() > 100
                ? document.getDescription().substring(0, 100) + "..."
                : document.getDescription());
        
        // 尝试从图片列表中获取第一张作为分享封面
        if (StringUtils.hasText(document.getCoverImageUrl())) {
            shareInfo.setCoverImage(document.getCoverImageUrl());
        } else if (StringUtils.hasText(document.getImageUrls())) {
            try {
                List<String> imageUrls = objectMapper.readValue(document.getImageUrls(), new TypeReference<>() {});
                if (imageUrls != null && !imageUrls.isEmpty()) {
                    shareInfo.setCoverImage(imageUrls.get(0));
                }
            } catch (Exception e) {
                log.warn("解析分享封面图片失败: {}", e.getMessage());
            }
        }

        // TODO: 应从配置中读取前端页面的基础URL，而不是硬编码
        String frontendBaseUrl = "http://localhost:3000"; 
        String shareUrl = frontendBaseUrl + "/document/detail/" + id;
        shareInfo.setShareUrl(shareUrl);

        // 使用公共服务生成二维码URL
        try {
            String qrCodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + 
                java.net.URLEncoder.encode(shareUrl, java.nio.charset.StandardCharsets.UTF_8);
            shareInfo.setQrCodeUrl(qrCodeUrl);
        } catch (Exception e) {
             log.error("生成分享二维码URL编码失败", e);
        }

        // 构建便于复制粘贴的分享文本
        shareInfo.setShareText(String.format("【%s】%s - 南方少数民族语言文化资源平台 %s", 
            document.getTitle(), 
            shareInfo.getDescription() != null ? shareInfo.getDescription() : "",
            shareUrl));

        shareInfo.setShareTime(LocalDateTime.now());
        log.info("为文档ID {} 生成分享信息成功", id);
        return shareInfo;
    }
} 
